open Errors
;;

let globalenv = ref [] 
;;

let localenv = ref [] 
;;

let recorddecenv = ref []
;;

let fundecenv = ref []
;;

let fundefenv = ref []
;;

let open_localenv locals =
  localenv := locals
;;

let close_localenv () =
  localenv := [] 
;;

let open_globalenv globals =   
 globalenv := globals; 
;;

let fun_sort id = 
  try
    List.assoc id !fundecenv
  with
      Not_found -> raise (Unknown_ident id)
;;

let fun_delcared id =
  List.mem_assoc id !fundecenv
;;

let fun_defined id =
  List.mem_assoc id !fundefenv
	
let record_declared id =
	List.mem_assoc id !recorddecenv
	
let declare_record (rname, rmembers) =	
	if List.mem_assoc rname !recorddecenv then
		raise Name_clash4;
	recorddecenv := (rname, rmembers)::(!recorddecenv)
;;	

let declare_fun (fname, ftype) =
  try
    if ftype <> fun_sort fname then
      raise (Sort_error fname)
  with
      Unknown_ident _ -> fundecenv := (fname, ftype)::(!fundecenv)
;;

let define_fun (fname, ftype) =
  if fun_defined fname then
    raise Name_clash2;
  declare_fun (fname, ftype);
  fundefenv := (fname, ftype)::(!fundefenv)
;;

let ident_type id =
  try 
    List.assoc id !localenv
  with
      Not_found -> 
	try 
	  List.assoc id !globalenv
	with
	    Not_found -> raise (Unknown_ident id)
;;

let fields_sort rname =
  List.assoc rname !recorddecenv
;;

let field_sort rname fname =
  List.assoc fname (fields_sort rname)

let rec find_field_index name fields = match fields with
  | [] -> raise (Unknown_ident name)
  | (fname, ftype) :: fs -> 
      if fname = name then
	0
      else
	1 + find_field_index name fs
;;

let field_index rname fname =
  find_field_index fname (fields_sort rname)

